package com.ch.nettyplus.server;

import com.ch.nettyplus.server.autoconfigure.NettyPlusServerProperties;
import com.ch.nettyplus.server.channel.ServerChannelHandlerFactory;
import com.ch.nettyplus.server.channel.StringChannelHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

/**
 * @author CH
 * @data 2022/1/7
 */
@Slf4j
@EnableConfigurationProperties(NettyPlusServerProperties.class)
public class NettyPlusServerBootstrap implements InitializingBean {
    @Autowired
    private NettyPlusServerProperties properties;
    @Autowired
    private ServerChannelHandlerFactory serverChannelHandlerFactory;
    @Autowired
    private ServiceLocator serviceLocator;

    private Integer start = 0;
    @Override
    public void afterPropertiesSet() {
        log.info("状态:{}", properties.getLog().isStatus());
        log.info("级别:{}", properties.getLog().getLogLevel());
        if (properties.isStatus()) {
            initNettyServerChannel();
            initNettyServer();
        }
    }

    /**
     * 初始化netty-server的channel
     */
    private void initNettyServerChannel() {
        log.info("初始化channel");
        // 日志配置
        if (properties.getLog().isStatus()) {
            serverChannelHandlerFactory.getServerChannelHandlers().add(new LoggingHandler(properties.getLog().getLogLevel()));
        }
        // 心跳
        if (properties.getHeart().isStatus()) {
            serverChannelHandlerFactory.getServerChannelHandlers().add(
                    new IdleStateHandler(
                            properties.getHeart().getReaderIdleTime(),
                            properties.getHeart().getWriterIdleTime(),
                            properties.getHeart().getAllIdleTime(),
                            properties.getHeart().getTimeUnit())
            );
        }
        if (serviceLocator.getMap().isEmpty()) {
            // 默认配置
            serverChannelHandlerFactory.getServerChannelHandlers().add(new StringEncoder());
            serverChannelHandlerFactory.getServerChannelHandlers().add(new StringDecoder());
            serverChannelHandlerFactory.getServerChannelHandlers().add(new StringChannelHandler());
        } else {
            // 自定义配置
            for (String key : serviceLocator.getMap().keySet()) {
                System.out.println(key);
                serverChannelHandlerFactory.getServerChannelHandlers().add((ChannelHandler) serviceLocator.getService(key));
            }
        }
    }

    /**
     * 初始化netty服务端
     */
    public void initNettyServer() {
        EventLoopGroup boss = new NioEventLoopGroup(properties.getBossThreads());
        EventLoopGroup work = new NioEventLoopGroup(properties.getWorkThreads());
        try {
            log.info("启动netty服务端，端口号为:{}", properties.getPost());
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch){
                            if(start == 0){
                                start =1;
                                ChannelHandler[] channelHandlers = serverChannelHandlerFactory.getServerChannelHandlers().toArray(ChannelHandler[]::new).clone();
                                ch.pipeline().addLast(channelHandlers);
                            }else{
                                for (ChannelHandler c: serverChannelHandlerFactory.getServerChannelHandlers()) {
                                    ChannelHandler.Sharable q=c.getClass().getAnnotation(ChannelHandler.Sharable.class);
                                    if (q!=null){
                                        ch.pipeline().addLast(c);
                                    }
                                }
                            }

                        }
                    });
            ChannelFuture channelFuture = bootstrap.bind(properties.getPost()).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }
}
